package org.grottarossa.ui.core.components.tables;


import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Hashtable;

import org.grottarossa.template.data.enums.EnumDataType;
import org.grottarossa.template.data.pojo.table.Cell;
import org.grottarossa.template.data.pojo.table.Record;
import org.grottarossa.ui.core.container.TableContainer;

import com.vaadin.data.Container;
import com.vaadin.data.util.IndexedContainer;

/***
 * Estende TableContainer decorandolo con la gestione dei filtri
 * @author 
 *
 */
public class FilteredContainerWrapper extends TableContainer
{
	/*** Mappa dei valori dei filtri settati ***/
	protected Hashtable<String, Object> m_filters = new Hashtable<String, Object>();

	/*** ID dell'Item della riga dei filtri ***/
	private Object m_filterItemId = null;

	/***
	 * IMPORTANTE: La struttura del container da wrappare deve essere definita
	 * @param container
	 */
	public FilteredContainerWrapper(TableContainer container)
	{
		setDataTable(container.getDataTable());
	}

	@Override
	protected void populateRecords()
	{
		removeItemsButNotFilter();

		ArrayList<Record> records = m_dataTable.getRecords();
		ArrayList<Cell> headerCells = m_dataTable.getHeader().getHeaderCells();

		if(m_filterItemId == null)
			m_filterItemId = addItem();

		for(int i=0;i<records.size();i++)
		{
			if(applyFilter(records.get(i)))
				addRow(records.get(i), headerCells);
		}
	}

	/***
	 * Restituisce un valore che indica se la riga deve essere scartata o meno in base ai filtri
	 * @param record
	 * @return
	 */
	private boolean applyFilter(Record record)
	{
		ArrayList<Cell>cellList = record.getCells();
		ArrayList<Cell> headerCells = m_dataTable.getHeader().getHeaderCells();

		for(int j=0;j<cellList.size();j++)
		{
			String propertyName = headerCells.get(j).getValue().toString();

			if(m_filters!= null &&
				m_filters.containsKey(propertyName) &&
				m_filters.get(propertyName) != null &&
				!m_filters.get(propertyName).equals(""))
				{
					EnumDataType type = headerCells.get(j).getDataType();

					if(cellList.get(j).getValue() == null)
						return false;

					if(type == EnumDataType.String || type == EnumDataType.BigDecimal ||
						type == EnumDataType.Integer|| type == EnumDataType.LongText)
					{
						if(!cellList.get(j).getValue().toString().toLowerCase().
								startsWith(m_filters.get(propertyName).toString().toLowerCase()))
							return false;
					}
					else if(type == EnumDataType.Calendar)
					{
						int filterYear = ((GregorianCalendar)m_filters.get(propertyName)).get(Calendar.YEAR);
						int filterDay = ((GregorianCalendar)m_filters.get(propertyName)).get(Calendar.DAY_OF_MONTH);
						int filterMonth = ((GregorianCalendar)m_filters.get(propertyName)).get(Calendar.MONTH);

						int year = ((GregorianCalendar)cellList.get(j).getValue()).get(Calendar.YEAR);
						int day = ((GregorianCalendar)cellList.get(j).getValue()).get(Calendar.DAY_OF_MONTH);
						int month = ((GregorianCalendar)cellList.get(j).getValue()).get(Calendar.MONTH);

						if( filterYear != year || filterDay != day || filterMonth != month)
							return false;
					}

				}
		}

		return true;
	}

	/***
	 * Rimuove tutte le righe ad eccezione della riga dei filtri
	 */
	private void removeItemsButNotFilter()
	{
		ArrayList<Object> toRemove = new ArrayList<Object>();

		for(Object id : getItemIds())
		{
			if(m_filterItemId != id)
				toRemove.add(id);
		}

		for(Object id : toRemove)
		{
			removeItem(id);
		}
	}

	/***
	 * Restituisce la riga dei filtri
	 * @return
	 */
	public Object getFilterItem()
	{
		return m_filterItemId;
	}

	/***
	 * Imposta il valore di un filtro
	 * @param propertyName
	 * @param value
	 */
	public void setFilter(String propertyName, Object value)
	{
		if(m_filters == null)
			m_filters = new Hashtable<String, Object>();

		m_filters.put(propertyName, value);

		populateRecords();
	}

	/***
	 * Rimuove un valore di filtraggio
	 * @param propertyName
	 */
	public void removeFilter(String propertyName)
	{
		if(m_filters == null)
			m_filters = new Hashtable<String, Object>();

		m_filters.remove(propertyName);

		populateRecords();
	}

	/***
	 * Restituisce la lista di valori data una colonna
	 * @param propertyId Nome della colonna
	 * @return
	 */
	public ArrayList<Object> getPropertyValues(Object propertyId)
	{
		ArrayList<Object> values = new ArrayList<Object>();

		Cell propertyCell = null;

		int i=0;

		for(Cell c : m_dataTable.getHeader().getHeaderCells())
		{
			if(c.getValue() != null && c.getValue().equals(propertyId))
			{
				propertyCell = c;
				break;
			}

			i++;
		}

		if(propertyCell == null)
			return values;

		for(Record r : m_dataTable.getRecords())
		{
			for(Cell c: r.getCells())
			{
				if(i==0)
				{
					Object value = c.getValue();

					if(!values.contains(value))
						values.add(value);

					break;
				}

				i--;
			}
		}

		return values;
	}
}
